#include "cledMatrixRGB.h"
#include "cledMatrix.h"
#include "UGUI/ugui.h"
#include "LCD/lcd.h"
#include "cledMatrixRGB.h"
#include "Curve/hsv.h"
#include <math.h>
#include <string.h>
#include <stdlib.h>

static hsv_t RandomHSVColor()
{
    hsv_t hsv;

    hsv.hue = rand() % 360;
    hsv.saturation = 255;
    hsv.value = 255;

    return hsv;
}
static uint32_t RandomRGBColor()
{
    hsv_t hsv = RandomHSVColor();
    return (hsv2rgb(&hsv));
}
static uint32_t Enlight(uint32_t color, float value)
{
    hsv_t hsv;
    rgb2hsv(color, &hsv);

    hsv.value *= value;

    return (hsv2rgb(&hsv));
}
static unsigned char InterpolateChanel(unsigned char a, unsigned char b, float x)
{
    return (int) ((b - a) * x + a);
}
#define RGBGetRValue(rgb)   (rgb & 0x000000FF)
#define RGBGetGValue(rgb)   ((rgb >> 8) & 0x000000FF)
#define RGBGetBValue(rgb)   ((rgb >> 16) & 0x000000FF)
#define ToRGBColor(r, g, b) ((uint32_t)((b << 16) | (g << 8) | (r)))
static uint32_t Interpolate(uint32_t color1, uint32_t color2, float fraction)
{
    return ToRGBColor(
                InterpolateChanel(RGBGetRValue(color1), RGBGetRValue(color2), fraction),
                InterpolateChanel(RGBGetGValue(color1), RGBGetGValue(color2), fraction),
                InterpolateChanel(RGBGetBValue(color1), RGBGetBValue(color2), fraction)
                );
}
/*************************************************************************************************\
|        Breathing [9]                                                                              |
\*************************************************************************************************/
void cledMatrixBreathing_Init(void)    // 呼吸
{
    mParams.time = 1000.0;
    mParams.FPS = 60;
    mParams.Speed = 100;
    mParams.Slider2Val = 30;
    mParams.shape = 0;
    mParams.progress = 0.f;
}

void cledMatrixBreathing(const uint32_t cols, const uint32_t rows)    // 呼吸
{
     mParams.progress += (( mParams.Speed / 100.0) / (float) mParams.FPS);

     hsv_t CurrentColor;
    if(mParams.progress >= 3.14159) // PI
    {
        mParams.progress -= 3.14159;

//        if(RandomColorsEnabled)
//        {
//           CurrentColor = ColorUtils::RandomHSVColor();
//        }
//        else
//        {
//           rgb2hsv(UserColors[0], &CurrentColor);
//        }
        CurrentColor = RandomHSVColor();
    }

    CurrentColor.value = pow(sin(mParams.progress),3) * 255;

    //for (ControllerZone* controller_zone: controller_zones)
//    {
//        controller_zone->SetAllZoneLEDs(hsv2rgb(&CurrentColor), Brightness);
//    }
    for (uint32_t col_id = 0; col_id < cols; col_id++)
    {
        for (uint32_t row_id = 0; row_id < rows; row_id++)
        {
           ugui_pset(col_id, row_id, hsv2rgb(&CurrentColor));
        }
    }
}

/*************************************************************************************************\
|        BreathingCircle [9]                                                                              |
\*************************************************************************************************/
void cledMatrixBreathingCircle_Init(void)    // 呼吸循环
{
    mParams.time = 1000.0;
    mParams.FPS = 60;
    mParams.Speed = 20;
    mParams.Slider2Val = 3;
    mParams.shape = 0;
    mParams.progress = 0.f;
}
static uint32_t BreathingCircle_GetColor(float x, float y, float w, float h)
{
    //float distance = std::min<float>(1.0, sqrt(pow(0.5 - x/w, 2) + pow(0.5 - y/h, 2)));
    float distance = sqrt(pow(0.5 - x/w, 2) + pow(0.5 - y/h, 2));
    if(distance>1.0f) distance=1.0f;

    if(distance > mParams.progress || distance < mParams.progress - mParams.Slider2Val/(0.5*(w+h)))
        return 0x00;//ColorUtils::OFF();

    //return UserColors[0];
    //return /*ColorUtils::*/RandomRGBColor();
    hsv_t tmp;
    //tmp.hue = pow(sin(mParams.progress),3) * 255;
    tmp.hue = (int) (300 * (mParams.progress) + 0) % 360;
    tmp.saturation =  255;
    tmp.value =  255;
    return hsv2rgb(&tmp);
}

void cledMatrixBreathingCircle(const uint32_t cols, const uint32_t rows)    // 呼吸循环
{
    for (uint32_t col_id = 0; col_id < cols; col_id++)
    {
        for (uint32_t row_id = 0; row_id < rows; row_id++)
        {
            uint32_t color = BreathingCircle_GetColor(col_id, row_id, cols-1, rows-1);

            //int LedID = controller_zones[i]->controller->zones[controller_zones[i]->zone_idx].matrix_map->map[((row_id * cols) + col_id)];
            //int LedID = (row_id * cols) + col_id;
            //controller_zone->SetLED(start_idx + LedID, color, Brightness);
            ugui_pset(col_id, row_id, color);
        }
    }
    mParams.time += (float) mParams.Speed / (float) mParams.FPS;
    mParams.progress = 0.35 * (1 + sin(0.1 * mParams.time));
    //mParams.progress = sin(0.1 * mParams.time);
}

/*************************************************************************************************\
|        Comet [9]                                                                              |
\*************************************************************************************************/
void cledMatrixComet_Init(void)    // 彗星
{
    mParams.time = 1000.0;
    mParams.FPS = 60;
    mParams.Speed = 25;
    mParams.Slider2Val = 50;
    mParams.shape = 0;
    mParams.progress = 0.f;
}
static uint32_t Comet_GetColor(unsigned int i, unsigned int width)
{
    float comet_size = 0.01 * mParams.Slider2Val * width;

    float position = mParams.progress * 2 * width;
    hsv_t tmp;

    if(i > position)
    {
        return 0x00;//ColorUtils::OFF();
    }

    float distance = position - i;

    double value;

    if(distance > comet_size)
    {
        value = 0;
    }
    else if(distance == 0)
    {
        value = 1;
    }
    else
    {
        value = 1 - (distance / comet_size);
    }

    //if(RandomColorsEnabled)
    {
        tmp.hue = (int) (1000 * (mParams.time) + (distance / comet_size) * 360) % 360;
        tmp.saturation = pow(value, 0.2) * 255;
        tmp.value = pow(value, 3) * 255;
    }
//    else
//    {
//        hsv_t user_hsv;
//        rgb2hsv(UserColors[0], &user_hsv);

//        tmp.hue = user_hsv.hue;
//        tmp.saturation = pow(value, 0.2) * user_hsv.saturation;
//        tmp.value = pow(value, 3) * user_hsv.value;
//    }

    return (hsv2rgb(&tmp));
}
void cledMatrixComet(const uint32_t cols, const uint32_t rows)    // 彗星
{
    int reverse = 0;
    for (uint32_t col_id = 0; col_id < cols; col_id++)
    {
        uint32_t color = Comet_GetColor(reverse ? cols - col_id - 1: col_id, cols);

        for (uint32_t row_id = 0; row_id < rows; row_id++)
        {
            //int LedID = controller_zones[i]->controller->zones[controller_zones[i]->zone_idx].matrix_map->map[((row_id * cols) + col_id)];
            //int LedID = (row_id * cols) + col_id;
            //controller_zone->SetLED(start_idx + LedID, color, Brightness);
            ugui_pset(col_id, row_id, color);
        }
    }
    mParams.time += 0.01 * mParams.Speed / (float) mParams.FPS;
    float whole;
    mParams.progress = modf(mParams.time, &whole);
}

/*************************************************************************************************\
|        Fill [9]                                                                              |
\*************************************************************************************************/
static double old_progress = 0;
static uint32_t random;
void cledMatrixFill_Init(void)    // 充满
{
    mParams.time = 1000.0;
    mParams.FPS = 60;
    mParams.Speed = 50;
    mParams.Slider2Val = 30;
    mParams.shape = 0;
    mParams.progress = 0.f;
    random = /*ColorUtils::*/RandomRGBColor();
}
static uint32_t Fill_GetColor(unsigned int idx, unsigned int width)
{
    double position = mParams.progress * width;

    double distance = position - idx;

    //uint32_t color = RandomColorsEnabled ? random : UserColors[0];
    uint32_t color = random;

    if(distance > 1)
    {
        return color;
    }

    if(distance > 0)
    {
        return /*ColorUtils::*/Enlight(color, distance);
    }

    return 0x00;//ColorUtils::OFF();
}
void cledMatrixFill(const uint32_t cols, const uint32_t rows)    // 充满
{
    int reverse = 0;
    for (uint32_t col_id = 0; col_id < cols; col_id++)
    {
        uint32_t color = Fill_GetColor(reverse ? cols - col_id - 1: col_id, cols);

        for (uint32_t row_id = 0; row_id < rows; row_id++)
        {
            //int LedID = controller_zones[i]->controller->zones[controller_zones[i]->zone_idx].matrix_map->map[((row_id * cols) + col_id)];
            //int LedID = (row_id * cols) + col_id;
            //controller_zone->SetLED(start_idx + LedID, color, Brightness);
            ugui_pset(col_id, row_id, color);
        }
    }

    mParams.time += 0.01 * mParams.Speed / (float) mParams.FPS;
    float whole;

    old_progress = mParams.progress;

    mParams.progress = modf(mParams.time, &whole);

    if(old_progress > mParams.progress/* && RandomColorsEnabled*/)
    {
        random = /*ColorUtils::*/RandomRGBColor();
    }
}

/*************************************************************************************************\
|        Marquee [9]                                                                              |
\*************************************************************************************************/
void cledMatrixMarquee_Init(void)    // 大天幕
{
    mParams.time = 1000.0;
    mParams.FPS = 60;
    mParams.Speed = 50;
    mParams.Slider2Val = 2;
    mParams.shape = 0;
    mParams.progress = 0.f;
    mParams.hsv.saturation = 255;
    mParams.hsv.value = 255;
    mParams.hsv.hue = 0;
}
static uint32_t Marquee_GetColor(unsigned int i)
{
    unsigned int spacing = mParams.Slider2Val;

//    RandomColorsEnabled = true;
//    return (i + (int) progress) % spacing == 0 ?
//                RandomColorsEnabled ?
//                    RGBColor(hsv2rgb(&mParams.hsv)) : UserColors[0]
//              : ColorUtils::OFF();
    return (i + (int) mParams.progress) % spacing == 0 ? (hsv2rgb(&mParams.hsv)) : 0x00;
}
void cledMatrixMarquee(const uint32_t cols, const uint32_t rows)    // 大天幕
{
    int reverse = 0;
    for (uint32_t col_id = 0; col_id < cols; col_id++)
    {
        uint32_t color = Marquee_GetColor(reverse ? cols - col_id - 1: col_id);

        for (uint32_t row_id = 0; row_id < rows; row_id++)
        {
            //int LedID = controller_zones[i]->controller->zones[controller_zones[i]->zone_idx].matrix_map->map[((row_id * cols) + col_id)];
            //int LedID = (row_id * cols) + col_id;
            //controller_zone->SetLED(start_idx + LedID, color, Brightness);
            ugui_pset(col_id, row_id, color);
        }
    }
    mParams.progress += 0.1 * mParams.Speed / (float) mParams.FPS;

    //if(RandomColorsEnabled)
    {
        mParams.hsv.hue++;
        mParams.hsv.hue%=360;
    }
}
struct Tile {
    hsv_t hsv;
    float brightness;// = 0.f;
    float decrease_speed_mult;// = 1.f;
};
static struct Tile tiles[41*41];
/*************************************************************************************************\
|        Mosaic [9]                                                                              |
\*************************************************************************************************/
void cledMatrixMosaic_Init(void)    // 马赛克
{
    mParams.time = 1000.0;
    mParams.FPS = 60;
    mParams.Speed = 10;
    mParams.Slider2Val = 30;
    mParams.shape = 0;
    mParams.progress = 0.f;
    memset(tiles, 0x00, sizeof(tiles));
}
static void Mosaic_UpdateTiles(void)
{
    unsigned int rarity = mParams.Slider2Val;
    struct Tile* tile=NULL;

    for(uint32_t i=0; i<(sizeof(tiles)/sizeof(tiles[0])); i++)
    {
        tile=&tiles[i];
        if(tile->brightness <= 0.f)
        {
            if(rand() % rarity == 0)
            {
                tile->brightness = 1.f;
                tile->decrease_speed_mult = ((double) rand() / (RAND_MAX)) + 1;

//                if(RandomColorsEnabled)
//                {
//                    tile.hsv = ColorUtils::RandomHSVColor();
//                }
//                else
//                {
//                    rgb2hsv(UserColors[rand() % UserColors.size()], &tile.hsv);
//                }
                tile->hsv = /*ColorUtils::*/RandomHSVColor();
            }
        }

        tile->brightness -= 0.0005 * mParams.Speed * tile->decrease_speed_mult;

        tile->hsv.value = tile->brightness > 0 ?tile->brightness * 255 : 0;
    }
}
void cledMatrixMosaic(const uint32_t cols, const uint32_t rows)    // 马赛克
{
    Mosaic_UpdateTiles();
    for (uint32_t col_id = 0; col_id < cols; col_id++)
    {
        for (uint32_t row_id = 0; row_id < rows; row_id++)
        {
           int idx = (row_id * cols) + col_id;
           //int LedID = controller_zones[i]->map()[idx];
           //int LedID = (row_id * cols) + col_id;
           uint32_t color = hsv2rgb(&tiles[idx].hsv);
           //controller_zone->SetLED(start_idx + LedID, color, Brightness);
           ugui_pset(col_id, row_id, color);
        }
    }
}

/*************************************************************************************************\
|        MotionPoint [9]                                                                              |
\*************************************************************************************************/
void cledMatrixMotionPoint_Init(void)    // 运动点
{
    mParams.time = 1000.0;
    mParams.FPS = 60;
    mParams.Speed = 25;
    mParams.Slider2Val = 30;
    mParams.shape = 0;
    mParams.progress = 0.f;
}
uint32_t current=0x00;
static uint32_t MotionPoint_GetColor(unsigned int w, unsigned int x, double t)
{
    if(w == 0)
    {
        w = 1;
    }

    float distance = fabs(x - t * (w-1));

    if(distance > 2)
    {
        return 0x00;//background;
    }

//    if(RandomColorsEnabled)
//    {
//        if(t <= 0.0005 || t >= 0.9995)
//        {
//            current  = ColorUtils::RandomRGBColor();
//        }
//    }
//    else
//    {
//        current = UserColors[0];
//    }
    if(t <= 0.0005 || t >= 0.9995)
    {
        current  = /*ColorUtils::*/RandomRGBColor();
    }

    return /*ColorUtils::*/Interpolate(current, /*background*/0x00, distance / 2.f);
}
void cledMatrixMotionPoint(const uint32_t cols, const uint32_t rows)    // 运动点
{
    double t = (1 + sin(mParams.progress)) / 2.f;
    for (uint32_t col_id = 0; col_id < cols; col_id++)
    {
        uint32_t color = MotionPoint_GetColor(cols, col_id, t);

        for (uint32_t row_id = 0; row_id < rows; row_id++)
        {
            //int LedID = controller_zone->controller->zones[controller_zone->zone_idx].matrix_map->map[((row_id * cols) + col_id)];
            //int LedID = (row_id * cols) + col_id;
            //controller_zone->SetLED(start_idx + LedID, color, Brightness);
            ugui_pset(col_id, row_id, color);
        }
    }
    mParams.progress += 0.1 * (float) mParams.Speed / (float) mParams.FPS;
}

/*************************************************************************************************\
|        MotionPoints [9]                                                                              |
\*************************************************************************************************/
enum Dir {
    LEFT = 0,
    RIGHT = 1,
    UP = 2,
    DOWN = 3
};
struct MovingPoint
{
    float x;// = 0.f;
    float y;// = 0.f;

    float speed_mult;// = 1.f;

    enum Dir dir;

    uint32_t color;
};
void PointMove(struct MovingPoint* const point, float delta)
{
    switch(point->dir)
    {
        case LEFT:
        {
            point->x -= delta;
            break;
        }

        case RIGHT:
        {
            point->x += delta;
            break;
        }

        case UP:
        {
            point->y -= delta;
            break;
        }

        case DOWN:
        {
            point->y += delta;
            break;
        }
    }
}

int PointIsOut(struct MovingPoint* const point)
{
    return point->x < 0.f || point->y < 0.f || point->x > 1.f || point->y > 1.f;
}

void PointInit(struct MovingPoint* const point, uint32_t c)
{
    point->dir = rand() % 4;//static_cast<Dir>(rand() % 4);
    point->speed_mult = ((double) rand() / (RAND_MAX)) + 1;
    point->color = c;

    switch(point->dir)
    {
        case LEFT:
        {
            point->x = 1.f;
            point->y = ((double) rand() / (RAND_MAX));
            break;
        }

        case RIGHT:
        {
            point->x = 0.f;
            point->y = ((double) rand() / (RAND_MAX));
            break;
        }

        case UP:
        {
            point->x = ((double) rand() / (RAND_MAX));
            point->y = 1.f;
            break;
        }

        case DOWN:
        {
            point->x = ((double) rand() / (RAND_MAX));
            point->y = 0.f;
            break;
        }
    }
}
struct MovingPoint points[128];
static uint16_t pointsSize=0;
static void MotionPoints_SetSlider2Val(unsigned int value)
{
    mParams.Slider2Val = value;
    //points.clear();
    pointsSize=0;

    //UserColors.resize(2);

    for(unsigned int i = 0; i < value; i++)
    {
        //MovingPoint point;
        //point.Init(RandomColorsEnabled ? ColorUtils::RandomRGBColor() : UserColors[rand() % UserColors.size()]);
        //point.Init(ColorUtils::RandomRGBColor());
        //points.push_back(point);
        PointInit(&points[i], RandomRGBColor());
        pointsSize++;
    }
}
void cledMatrixMotionPoints_Init(void)    // 运动点
{
    mParams.time = 1000.0;
    mParams.FPS = 60;
    mParams.Speed = 50;
    mParams.Slider2Val = 4;
    mParams.shape = 0;
    mParams.progress = 0.f;
    MotionPoints_SetSlider2Val(8);
}
static void MotionPoints_UpdatePoints()
{
    for(uint16_t i=0; i<pointsSize; i++)//for(MovingPoint& point: points)
    {
        PointMove(&points[i], 0.0001 * mParams.Speed * points[i].speed_mult);

        if(PointIsOut(&points[i]))
        {
            //point.Init(RandomColorsEnabled ? ColorUtils::RandomRGBColor() : UserColors[rand() % UserColors.size()]);
            PointInit(&points[i], /*ColorUtils::*/RandomRGBColor());
        }
    }
}

static uint32_t MotionPoints_GetColor(float x, float y, float w, float h)
{
    for(uint16_t i=0; i<pointsSize; i++)//for(MovingPoint& point: points)
    {
       float distance = sqrt(pow(points[i].x * w - x, 2) + pow(points[i].y * h - y, 2));

       if(distance <= 1)
       {
           return /*ColorUtils::*/Enlight(points[i].color, 1 - distance);
       }
    }

    return 0x00;//ColorUtils::OFF();
}
void cledMatrixMotionPoints(const uint32_t cols, const uint32_t rows)    // 运动点
{
    MotionPoints_UpdatePoints();
    for (uint32_t col_id = 0; col_id < cols; col_id++)
    {
        for (uint32_t row_id = 0; row_id < rows; row_id++)
        {
            uint32_t color = MotionPoints_GetColor(col_id, row_id, cols, rows);

            //int LedID = controller_zones[i]->controller->zones[controller_zones[i]->zone_idx].matrix_map->map[((row_id * cols) + col_id)];
            //int LedID = (row_id * cols) + col_id;
            //controller_zone->SetLED(start_idx + LedID, color, Brightness);
            ugui_pset(col_id, row_id, color);
        }
    }
}

/*************************************************************************************************\
|        Stack [9]                                                                              |
\*************************************************************************************************/
static uint32_t current_colors[41];
//static unsigned int stops[41*41];
//static float progress[41*41];
static unsigned int stops=0;
static uint32_t zone_colors;
static void Stack_ResetZone(void)
{
    stops = 41-1;
    mParams.progress = 0.f;

    for(unsigned int c = 0; c < 41; c++)
    {
        current_colors[c] = 0x00;//ColorUtils::OFF();
    }

    zone_colors = /*RandomColorsEnabled ? ColorUtils::*/RandomRGBColor();// : UserColors[0];
}
void cledMatrixStack_Init(void)    // 堆
{
    mParams.time = 1000.0;
    mParams.FPS = 60;
    mParams.Speed = 10;
    mParams.Slider2Val = 30;
    mParams.shape = 0;
    mParams.progress = 0.f;
    Stack_ResetZone();
}
uint32_t Stack_GetColor(unsigned int led_idx)
{
    unsigned int stop = stops;

    if(stop < led_idx)
    {
        return zone_colors;
    }

    float zone_progress = mParams.progress;

    float distance = fabs(zone_progress - led_idx);

    if(distance > 1)
    {
        return 0x00;//ColorUtils::OFF();
    }

    return /*ColorUtils::*/Enlight(zone_colors, 1 - distance);
}
void cledMatrixStack(const uint32_t cols, const uint32_t rows)    // 堆
{
    int reverse=0;
    // horizontal
    int horizontal=0;
    if(horizontal == 0)
    {
        for (uint32_t col_id = 0; col_id < cols; col_id++)
        {
            uint32_t color = Stack_GetColor(reverse ? cols - col_id - 1: col_id);
            current_colors[col_id] = color;

            for (uint32_t row_id = 0; row_id < rows; row_id++)
            {
                //int LedID = controller_zones[i]->controller->zones[controller_zones[i]->zone_idx].matrix_map->map[((row_id * cols) + col_id)];
                //int LedID = (row_id * cols) + col_id;
                //controller_zone->SetLED(start_idx + LedID, color, Brightness);
                ugui_pset(col_id, row_id, color);
            }
        }
    }
    // vertical
    else
    {
        for (uint32_t row_id = 0; row_id < rows; row_id++)
        {
            uint32_t color = Stack_GetColor(reverse ? rows - row_id - 1: row_id);
            current_colors[row_id] = color;

            for (uint32_t col_id = 0; col_id < cols; col_id++)
            {
                //int LedID = controller_zones[i]->controller->zones[controller_zones[i]->zone_idx].matrix_map->map[((row_id * cols) + col_id)];
                //int LedID = (row_id * cols) + col_id;
                //controller_zone->SetLED(start_idx + LedID, color, Brightness);
                ugui_pset(col_id, row_id, color);
            }
        }
    }
    float delta_progress = 0.1 * mParams.Speed / (float) mParams.FPS;

    mParams.progress += delta_progress * (sizeof(current_colors)/sizeof(current_colors[0]));

    if(mParams.progress >= stops)
    {
        stops--;

        if(stops == 0)
        {
            Stack_ResetZone();
        }

        mParams.progress = 0.f;
    }
}

/*************************************************************************************************\
|        Swap [9]                                                                              |
\*************************************************************************************************/
static uint32_t random1;
static uint32_t random2;
static uint32_t c1;
static uint32_t c2;
static uint32_t dir = 0;
static uint32_t old_dir = 0;
void cledMatrixSwap_Init(void)    // 交换
{
    mParams.time = 1000.0;
    mParams.FPS = 60;
    mParams.Speed = 10;
    mParams.Slider2Val = 30;
    mParams.shape = 0;
    mParams.progress = 0.f;
    random1 = /*ColorUtils::*/RandomRGBColor();
    random2 = /*ColorUtils::*/RandomRGBColor();
}
uint32_t Swap_GetColor(unsigned int i, unsigned int w)
{
    float x = dir ? mParams.progress : 1 - mParams.progress;
    return (i+1) <= x * (w+1) ? c1 : c2;
}
void cledMatrixSwap(const uint32_t cols, const uint32_t rows)    // 交换
{
    int reverse = 1;
    for (uint32_t col_id = 0; col_id < cols; col_id++)
    {
        uint32_t color = Swap_GetColor(reverse ? cols - col_id - 1: col_id, cols);

        for (uint32_t row_id = 0; row_id < rows; row_id++)
        {
            //int LedID = controller_zones[i]->controller->zones[controller_zones[i]->zone_idx].matrix_map->map[((row_id * cols) + col_id)];
            //int LedID = (row_id * cols) + col_id;
            //controller_zone->SetLED(start_idx + LedID, color, Brightness);
            ugui_pset(col_id, row_id, color);
        }
    }
    mParams.time += 0.1 * mParams.Speed / (float) mParams.FPS;

    float whole;

    mParams.progress = modf(mParams.time, &whole);
    //dir = (int) whole % 2;
    dir = ((int) mParams.time) % 2;

//    c1 = RandomColorsEnabled ? random1 : UserColors[0];
//    c2 = RandomColorsEnabled ? random2 : UserColors[1];
    c1 = random1;
    c2 = random2;

    if(old_dir == 0 && dir == 1)
    {
        random1 = /*ColorUtils::*/RandomRGBColor();
    }
    else if(old_dir == 1 && dir == 0)
    {
        random2 = /*ColorUtils::*/RandomRGBColor();
    }

    old_dir = dir;
}
static uint32_t c0;
float  p = 0.;
float  p_step =0.;
int   step = 0;
int   last_step = 0;
float  width = 0.;
float  h_width = 0.;
/*************************************************************************************************\
|        Visor [9]                                                                              |
\*************************************************************************************************/
void cledMatrixVisor_Init(void)    // 遮阳板
{
    mParams.time = 1000.0;
    mParams.FPS = 60;
    mParams.Speed = 50;
    mParams.Slider2Val = 20;
    mParams.shape = 0;
    mParams.progress = 0.f;
    c0 = RandomRGBColor();
    c1 = RandomRGBColor();
}
static uint32_t Visor_GetColor(float i, float count)
{
    // Constraint absolute minimum size
    //float w = std::max<float>(1.5/count, width);
    float w = 1.5/count;
    if(w<width) w=width;
    float x_step = p_step * (1.+ 4.*w) - 1.5*w;

    // dont divide by zero
    if(count <= 1)
    {
        count = 2;
    }

    float x = i / (count-1);
    float dist = x_step - x;


    // fade the head
    if(dist < 0)
    {
        //float l = std::max<float>(0.,std::min<float>((w+dist)/w, 1.));
        float l = (w+dist)/w;
        if(l>1.0) l=1.0;
        if(l<0) l=0;
        return step ? Enlight(c1, l) : Enlight(c0, l) ;
    }

    // fade the tail
    if(dist > w)
    {
        //float l = std::max<float>(0.,std::min<float>(1.-((dist-w)/w), 1.));
        float l = 1.-((dist-w)/w);
        if(l>1.0) l=1.0;
        if(l<0) l=0;
        return step ? Enlight(c0, l) : Enlight(c1, l) ;
    }

    // interpolate colors

    //float interp = std::min<float>(std::max<float>((w-dist)/w, 0.),1.);
    float interp = (w-dist)/w;
    if(interp<0) interp=0;
    if(interp>1) interp=1;

    return step ?
                /*ColorUtils::*/Interpolate(c0,c1,interp):
                /*ColorUtils::*/Interpolate(c1,c0,interp);

}
void cledMatrixVisor(const uint32_t cols, const uint32_t rows)    // 遮阳板
{
    // Caculate a few things outside the loop
    mParams.progress += 0.01 * ((float)mParams.Speed) / ((float)mParams.FPS);

    width = 0.01 * mParams.Slider2Val;          // [0-1] float, size of the visor
    h_width = 0.5 * width;              // [0-0.5] float, half width
    p = (mParams.progress - (long) mParams.progress);   // [0-1] float, 0 to 1 progress
    step = p < 0.5;                     // p in [0-0.5] = fist step, p in [0.5-1] = second step
    p_step =  step ? 2.*p : 2.*(1.- p); // [0-1] float, 0 to 1 progress within the step


    int flipping = (last_step != step);

    if(flipping) last_step = step;

    //if(flipping && RandomColorsEnabled)
    {
        c0 = /*ColorUtils::*/RandomRGBColor();
        c1 = /*ColorUtils::*/RandomRGBColor();
    }
//    else if(!RandomColorsEnabled)
//    {
//        c0 = UserColors[0];
//        c1 = UserColors[1];
//    }
    for (uint32_t col_id = 0; col_id < cols; col_id++)
    {
        uint32_t color = Visor_GetColor(col_id, cols);

        for (uint32_t row_id = 0; row_id < rows; row_id++)
        {
            //int LedID = controller_zone->controller->zones[controller_zone->zone_idx].matrix_map->map[((row_id * cols) + col_id)];
            //int LedID = (row_id * cols) + col_id;
            //controller_zone->SetLED(start_idx + LedID, color, Brightness);
            ugui_pset(col_id, row_id, color);
        }
    }
}


